在学习进程的时候,我们想fork一个子进程,然后就可以给他布置任务了
但是如果我们分成两个人开发,父子进程分别负责不同的任务,等待开发完成之后除了合并项目或者复制粘贴还有更好的办法吗
其实是有的,当子进程被创建后不想执行父进程代码时,就需要用到程序替换
主要是exec系列函数的用法
exec系列函数
这里一共有六个函数,但是是同一个系列的,也有一定的规律,如果他们替换失败了,返回值都是-1
execl这是里面最简单的函数,他的函数有两个,第一个是执行的程序路径,之后的是参数包,表示如何执行该程序
可以理解为前一个是环境变量,后一个是程序指令,只不过按单词分开,具体使用是这样的
例如
12345678910111213#include<stdio.h>#include<unistd.h>int main() { printf("程序替换\n"); int n = execl("/usr/bin/ls","ls","-a","-...
进程等待进程等待的过程其实是父进程等待子进程死亡的过程
进程等待的必要性如果子进程退出,父进程不进行处理,子进程会变成僵尸进程,有内存泄漏的风险
僵尸进程只有父进程有权处理,其他指令对其都没有效果了
父进程创建子进程是为了完成某项任务,当子进程结束后,父进程有必要了解任务完成的如何
父进程需要对子进程进行回收
进程等待的方法waitpid系统调用的返回值是pid_t,如果等待成功则返回进程pid,失败则返回-1
这个函数有三个参数,第一个参数是pid_t pid,表示需要等待的进程id,输入-1表示等待任一子进程结束
第二个参数是int* stat_loc,这是一个输出型参数,采用指针的方法获取子进程退出状态,如果我们不关心这个状态直接传入NULL即可
第三个参数是int options,默认为0,代表阻塞等待,也有非阻塞等待的情况
还有一个wait的系统调用,只有第二个参数,就相当于waitpid的默认使用情况
12345678910111213141516171819202122#include<sys/wait.h>#include<stdlib.h>...
进程终止我们之前在命令行界面要终止一个进程时直接ctrl+c来干掉一个进程是比较暴力的做法
实际上我们通常会使用一些函数调用接口或者系统调用接口来控制进程的退出
就像我们完成一个任务一样,有完成和未完成两种结果,完成也可以分为完美完成和不完美完成
对应下来就是三种结果,代码执行完成、结果正确;代码执行完成、结果不正确;代码异常终止
前两个都属于是程序正常退出,一般有三种常见的方法,main函数return返回、调用exit终止进程、调用_exit终止进程
而第三种则是异常退出,一般情况下异常往往是与信号相关的内容,我们之后再做介绍,这里我们只考虑ctrl+c终止进程
从main函数return返回在一开始学习C/C++时,在main函数结尾都会写一个return 0,当时的解释就是表示程序正常结束
那么也就说明有异常结束的情况了,首先要说明的一些情况是这样的
一个进程中只有一个main函数,也有的书中将函数称之为子程序,这是因为函数也可以return值,那么其实就可以说明,非main函数return时,表示这个函数完毕,而main函数执行到return时,说明这个进程执...
程序地址空间我们之前学习内存的时候,有说内存的分布大概是这样的
其中堆由下而上,栈由上而下
除此之外,实际上C/C++的常量字符串处于正文代码区,因此常量字符串是不允许修改的
其次虽然栈是由上而下的,但是数组和结构体的地址是从下而上开辟的,简单说就是a[0]的地址比a[1]的地址低
地址空间与物理内存我们考虑下面这样的代码
123456789101112131415161718192021222324252627#include <stdio.h> #include <unistd.h> #include <sys/types.h> #include <stdlib.h> int main() { int id=fork(); int tmp=10; if(id==0)//子进程执行的代码 { tmp=20; while(1) { ...
环境变量查看环境变量在上一篇文章中我们只说了查看某个环境变量的值,那么如何查看所有的环境变量呢
使用指令env即可
例如
这里我们也不需要全部记住,只需要记住一些比较常见的
PWD这个环境变量就是给pwd指令的结果了
HOME这里对应的就是cd ~命令了,找到家在哪里
那其实在我们登录Xshell时,他所做的工作就是认证信息,将bash加载到内存,形成进程,根据用户名初始化环境变量,进入家目录
这样我们其实就能理解为什么当我们直接改环境变量值的之后,直接重启Xshell就能恢复了,因为每一次都要重新加载初始化
获取环境变量那么在C语言中是如何获取环境变量呢
就是使用getenv()函数即可,返回值即为环境变量的值,参数是环境变量名称
例如
12char* ret = NULL;ret = getenv("PATH");
main()的第三个参数我们之前说了main的前两个参数,表示命令行参数表
1int main(int argc, char* argv[], char* env[])
这里的第三个参数其实就是环境变量的指针数组,他指向的就是环境变量...
进程间切换我们在之前讲过CPU在调度进程时,不是一个进程一直占用CPU,而是会过段时间就会放入其他进程,那么就一定存在进程切换的过程
运行到一半的进程数据去哪了第一个想到的问题就是,当一个进程中途被取下,再次放上去时,计算机怎么知道这个进程运行到哪里了
了解计算机组成原理的朋友都知道CPU中有一些寄存器,例如eax、ebx、esp、ebp、eip等
eax可以帮助函数返回一个值
esp和ebp用来维护函数的栈帧
eip则会保存当前代码运行到了哪一行
所以在进程运行时,这些寄存器就会临时保存进程产生的各种数据
这里需要注意的是,进程在切换时会不断的对自己的数据进行保存和恢复,当进程进行保存时是保存寄存器中的数据,而非寄存器本身,这些数据会被保存到进程的PCB中
进程被取下时,CPU数据是否会被删除事实上,一个进程被取下时,CPU不会删除他的临时数据,而是当下一个进程被放入时,直接进行覆盖
命令行参数我们之前在学习C/C++的时候,有的默认代码在main函数内也放置了两个参数
1int main(int argc, char* argv[]);
这两个参数也称之为命令...
僵尸进程僵尸状态进程本质上就是死亡状态
在进程死亡之后,不会直接对进程进行释放,而是先会处理一些后事
进程在结束退出的时候,也会有一些信息来表示任务完成的如何
一个最最直接的例子就是,C/C++中主函数的return0,在一开始学的时候很不理解为什么要return0,但其实0只是表示正常执行结束的信息,程序也可以返回1、2、3等内容来表示别的情况
当进程退出,但是还没有处理完后事的时候,就处于僵尸状态
变成僵尸状态的过程我们在退出进程的时候,需要一些信息来表示任务完成的如何,那么这些信息要交给谁呢,也就是这个return给了谁
答案就是父进程,当一个进程在退出的时候,退出信息会由操作系统写入到当前退出进程的PCB中,可以允许进程的代码和数据空间被释放,但是不允许进程的PCB被立即释放
所以僵尸状态的定义就是,当一个进程退出,但退出信息没有被父进程读取,此时退出进程的PCB没有被释放,就处于僵尸状态
但是当一个进程长期处于僵尸状态时,如果不及时处理,就会有内存泄漏的风险
我们可以用下面的代码来观察和僵尸进程
12345678910111213141516171819202...
聚类分析在模式识别、机器学习以及图像分割领域有着重要作用。k均值聚类由于算法的时间复杂度比较低,从而广泛应用于各类数据信息挖掘业务中
聚类的概念聚类指的是将物理或者抽象的对象集合分成由相似对象组成的多个类的过程
这个过程中的关键就是如何度量对象间的相似性
较为常见的指标由距离、密度等。我们把聚类完成之后的一组数据对象的集合称为簇,同一个簇内的对象相似性高,而不同的则反之,并且非监督学习没有预先定义好的分类
簇的划分直观上我们会把样本点散落在坐标系中,然后根据相似性放一起,这样自然就能形成一个示意图
如果在某一固定范围内,样本较为集中,其实就说明这一簇中的对象特征相似,而且有别于其他簇,例如扑克牌中的四种花色
但是当簇的特征不是那么明显的时候,我们没办法一眼就看出簇的个数,这时候就需要一个算法来划分,也就是k均值聚类算法
k均值聚类算法的核心首先我们介绍k均值聚类算法的工作流程
选取k个点,作为k个簇的中心,这个k是认为设定的参数
将数据对象分配到距离自己最近的簇中
假设样本集中由l个样本,每个样本都有n个特征,用$x_i$表示,假设我们要把这些样本分为k个簇$S={...